#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<math.h>
using namespace std;

template<typename Object>
class Vector
{
 public:
  explicit Vector(int initSize=0):theSize{ initSize},theCapacity{initSize+SPARE_CAPACITY} //define a Vector explicitly; Constructor 1
  {objects=new Object[theCapacity];}    //dynamic allocation

  Vector(const Vector & rhs): theSize {rhs.theSize},theCapacity{rhs.theCapacity},objects{nullptr}   //Constructor 2:to assign the following elements into objects as a prevention from revealing internal information.
  {
    objects=new Object[theCapacity];
    for(int k=0;k<theSize;++k)
      objects[k]=rhs.objects[k];
  }

  Vector & operator= (const Vector & rhs)//Overloading of = : to copy the elements in vector
  {
      Vector copy=rhs;
      swap(*this,copy);
      return *this;
  }

  ~Vector() //Destructor
  {
      delete [] objects;    //dynamic allocation
   }

 Vector(Vector && rhs):theSize{rhs.theSize},theCapacity{rhs.theCapacity},objects{rhs.objects}   //to give initial values
  {
    rhs.objects=nullptr; //it is a pointer so that its initial value should be a pointer which particularly is nullptr.
    rhs.theSize=0;
    rhs.theCapacity=0;
  }

  Vector & operator= (Vector && rhs) //Overloading of =: it's different from line 19 due to rhs in line 38 is a pointer
    {
      swap(theSize,rhs.theSize);
      swap(theCapacity,rhs.theCapacity);
      swap(objects,rhs.objects);

      return *this;
    }

  void resize(int newSize) //renew the size of the vector
  {
    if(newSize>theCapacity)
      reserve(newSize*2);
    theSize=newSize;
  }

  void reserve(int newCapacity) //renew the capacity of the vector
  {
    if(newCapacity<theSize)
      return;

    Object *newArray=new Object[newCapacity];
    for(int k=0;k<theSize;++k)
      newArray[k]=move(objects[k]);

    theCapacity=newCapacity;
    swap(objects,newArray);
    delete [] newArray; //A prevention from revealing internal information
  }

  Object & operator[](int index)    //Overloading of []:return to a/an vector/array;
    {return objects[index];}
  const Object & operator[](int index) const
  {return objects[index];}

  bool empty()const     //to determine whether the vector is a zero vector or not
  {return size()==0;}
  int size() const
  {return theSize;}
  int capacity() const
  {return theCapacity;}

  void push_back(const Object & x)  //to fill in the vector from the end of the vector one-by-one
  {
    if(theSize==theCapacity)
      reserve(2*theCapacity+1);
    objects[theSize++]=x;
  }

  void push_back(Object && x)
  {
    if(theSize==theCapacity)
    reserve(2*theCapacity+1);
    objects[theSize++]=move(x);
  }
  void pop_back() // delete the elements from front of the vector
  {
    --theSize;
  }

  const Object & back() const //get back to the previous element
  {
    return objects[theSize-1];
  }

  typedef Object * iterator;
  typedef const Object * const_iterator;

  iterator begin()      //point on the first element
  {return &objects[0];}
  const_iterator begin() const
  {return &objects[0];}
  iterator end()        //point on the last to the next element
  {return &objects[size()];}
  const_iterator end() const
  {return &objects[size()];}

  static const int SPARE_CAPACITY=16;

 private:
  int theSize;      //size of the vector
  int theCapacity;  //capacity of the vector
  Object *objects;  //a pointer in type of template that points to rhs

};
